/**
    @class Tram
    @brief Obiekt tramwaju poruszający się po torach

    Tramwaje pod względem budowy bardzo przypominają samochody: dziedziczą po tych samych klasach i mają te same charakterystyczne funkcje.
    Istotnym elementem jest fakt, że tramwaj przechowuje wskaźnik na tory, skąd pobiera informacje na temat kluczowych punktów a także rodzaju połączenia torów na wewnętrznym placu (proste lub łuk).
*/

#include "tram.h"
#include "qroundabout.h"
#include <QStyleOptionGraphicsItem>
#include <QPainterPath>
#include <QDebug>
#include <math.h>
#define PI 3.14159265358979323846264338327950288419716939937510

Tram::Tram(Rails* r, QRoundabout *qr, qreal dist) :
        QGraphicsItem(), _rails(r), _qr(qr), _color(Qt::white), _speed(3),
        _state(forward)
{
    qreal laneWidth = _qr->getLaneWidth();
    qreal bigWidth = (laneWidth - laneWidth/3 );
    qreal smallWidth = bigWidth * 2 /3;
    qreal length = 4 * laneWidth;
    /* powinien być szeroki jak samochoód
        _
       / \
      |   |
      |   |
       \_/
       */

    _tram = new QPainterPath(QPointF(smallWidth/2, length/2));  // prawy górny róg
    _tram->lineTo(bigWidth/2,  length/2 - length/6);
    _tram->lineTo(bigWidth/2, -length/2 + length/6);
    _tram->lineTo(smallWidth/2, -length/2 );    // prawy dolny róg
    _tram->lineTo(-smallWidth/2, -length/2 );    // lewy dolny róg
    _tram->lineTo(-bigWidth/2, -length/2 + length/6);
    _tram->lineTo(-bigWidth/2, +length/2 - length/6);
    _tram->lineTo(-smallWidth/2, length/2);     // lewy górny róg

    // trza wyliczyć pozycję startową na podstawie torów
    QLineF startLine = _rails->getSrcLine();
    startLine.setLength(dist);
    setPos(mapToParent(startLine.p2()));

    setRotation(360 - startLine.angle() + 90);
    _angle = rotation();
//    qDebug() << startLine.angle() << rotation();
}

void Tram::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    painter->setClipRect( option->exposedRect );
    painter->setPen(Qt::NoPen);
    QBrush b(_color);
    painter->setBrush(b);
    painter->drawPath(*_tram);

//    painter->setPen(Qt::SolidLine);
//    painter->drawLine(mapFromParent(_rails->getIntersectionPoint()), QPointF(0, 0));
//    painter->setPen(Qt::white);
//    painter->drawLine(mapFromParent(_rails->getDstLine().p1()),  QPointF(0, 0));
}

QRectF Tram::boundingRect() const
{
//    return QRectF(-200, -200, 400, 400);
    return _tram->boundingRect();
}

QPainterPath Tram::shape() const
{
    return *_tram;
}

void Tram::advance(int step)
{
    if (!step)
        return;

    switch (_state)
    {
        case forward:
            setPos(mapToParent(0, _speed)); break;
        case turning:
            turn();
            break;
        default: break;
    }


//        qDebug() << pos() << _rails->getSrcLine().p1() << pos() - _rails->getSrcLine().p1() << ( pos() - _rails->getSrcLine().p1() ).manhattanLength();
    if (( pos() - _rails->getSrcLine().p1() ).manhattanLength() < abs(int(_speed)))
    {
        setPos(_rails->getSrcLine().p1() );
        if (!_rails->isEllipseUsed())
        {
            qDebug() << "plan awaryjny" << _rails->getSrcLine().angleTo( QLineF( _rails->getSrcLine().p1(),  _rails->getDstLine().p1() ) );
            rotate( 180 - _rails->getSrcLine().angleTo( QLineF( _rails->getSrcLine().p1(),  _rails->getDstLine().p1() ) ));
        }
        else
        {
            _angle += 180 - _rails->getRotFactor();
            if (!_rails->getRotFactor())
                _speed *= -1;
        }
        _state = turning;
    }
}


/**
    Funkcja odpowiedzialna za animację tramwaju podczas skręcania, czyli między końcem lini źródła, a początkem linii celu.
    Animacja zależy od tego, czy połączenie torów zostało wykonane przy użyciu elipsy, czy nie.
  */
void Tram::turn()
{
    _color = Qt::red;

    if (_rails->isEllipseUsed())
    {
        // ten radius jest stopniowo zmieniany, aż jest równy odległości od  intersectionPoint do _DstLine.p1()
        qreal radius = QLineF(QPointF(0, 0), mapFromParent(_rails->getIntersectionPoint())).length();
        qreal wantedRadius =  QLineF(_rails->getIntersectionPoint(), _rails->getDstLine().p1()).length();
        if (radius !=  wantedRadius)
        {
            qreal radiusShift = wantedRadius / 10*QLineF(_rails->getSrcLine().p1(), _rails->getDstLine().p1()).length();  // trzeba by to podzielić przez tyle klatek, ile będzie trwała animacja....
            if (wantedRadius < radius)
                radiusShift *= -1;
            radius += radiusShift;
            if (abs(int(radius - wantedRadius)) < abs(int(_speed)))
                radius = wantedRadius;
        }

        qreal omega = _speed / radius * 180.0 / PI;
        _angle += omega;

        /* obracanie wokół punktu (x, y)*/
        qreal X = _rails->getIntersectionPoint().x();
        qreal Y = _rails->getIntersectionPoint().y();
        setPos(radius * cos(_angle / 180.0 * PI) + X, radius * sin(_angle / 180.0 * PI) + Y);

        setRotation(_angle);
    }
    else  // proste połączenie. Zostałem już odpowiednio obrócony, teraz tylko do przodu!
        setPos(mapToParent(0, _speed));

    // sprawdzamy, czy nie czas zakończyć skręcanie
    if (( pos() - _rails->getDstLine().p1() ).manhattanLength() < abs(int(_speed)))
    {
        setPos(_rails->getDstLine().p1() );
        _state = forward;
        _color = Qt::white;
        setRotation(360 - _rails->getDstLine().angle() - 90);
        qDebug() << rotation();
        if (!_rails->getRotFactor())
            _speed *= -1;
    }
}

void Tram::mousePressEvent(QGraphicsSceneMouseEvent *event)
{

}
